package org.wattdepot.cli;

import org.wattdepot.client.WattDepotClient;
import org.wattdepot.client.WattDepotClientException;
import org.wattdepot.resource.source.jaxb.Source;
import org.wattdepot.resource.source.jaxb.SourceIndex;
import org.wattdepot.resource.source.jaxb.SourceRef;
import org.wattdepot.util.tstamp.Tstamp;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.datatype.XMLGregorianCalendar;
import org.wattdepot.cli.command.CarboncontentCommand;
import org.wattdepot.cli.command.ChartPowerCommand;
import org.wattdepot.cli.command.FueltypesCommand;
import org.wattdepot.cli.command.Help;
import org.wattdepot.cli.command.ListPowerGeneratedDayCommand;
import org.wattdepot.cli.command.ListPowerGeneratedTimestampCommand;
import org.wattdepot.cli.command.ListSensordataDayCommand;
import org.wattdepot.cli.command.ListSensordataTimestamp;
import org.wattdepot.cli.command.ListSourceSummaryCommand;
import org.wattdepot.cli.command.ListSources;
import org.wattdepot.cli.command.ListTotalCommand;
import org.wattdepot.cli.command.TotalpowerCommand;
import org.wattdepot.cli.command.WattDepotCliCommand;
import org.wattdepot.cli.processor.WattDepotCliProcessor;

/**
 * A simple command line interface to WattDepot that shows basic connection and processing.
 * 
 * @author Anthony Xu & John Mack modified from code by Philip Johnson
 */
public class CommandLineInterface {
  /** The URL to the public WattDepot Server. */
  protected static final String hostUri = "http://server.wattdepot.org:8182/wattdepot/";
  /** Holds an instance of the WattDepot client. */
  protected static final WattDepotClient client = new WattDepotClient(hostUri);
  protected static final String LIST = "list";

  /** 
   * Accessor method for WattDepotClient object client. 
   * 
   * @return WattDepotClient object client.
   */
  public WattDepotClient getClient() {
    return client;
  }
  
  /** Carriage return on this operating system. */
  private String cr = System.getProperty("line.separator");

  /**
   * Connect to the service and execute some simple commands. Returns immediately if a connection to
   * the service could not be obtained.
   */
  public CommandLineInterface() {
    // Stop right away if we cannot contact server.
    if (!client.isHealthy()) {
      System.out.println("Failed to connect to " + client.getWattDepotUri());
      return;
    }
    // Indicate successful connection.
    System.out.println("Connected to " + client.getWattDepotUri());
  }

  /**
   * Returns a string containing a list of all public sources available on this server.
   * 
   * @return A list of sources as a string.
   * @throws WattDepotClientException If problems occur obtaining the list of sources.
   */
  public String getSourcesInfo() throws WattDepotClientException {
    StringBuffer buff = new StringBuffer(20);
    buff.append("All public sources:").append(cr);
    List<Source> sources = client.getSources();
    for (Source source : sources) {
      buff.append(source.getName()).append(cr);
    }
    return buff.toString();
  }

  /**
   * Returns a double indicating the current power generated by a sample source on November 1, 2009.
   * 
   * @param source The source we want the current power from.
   * @return A double indicating power generated.
   * @throws WattDepotClientException If problems occur obtaining the power value.
   */
  public double getPowerGenerated(Source source) throws WattDepotClientException {
    XMLGregorianCalendar now = null;
    try {
      now = Tstamp.makeTimestamp("2009-11-01");
    }
    catch (Exception e) {
      System.out.println("should never happen.");
    }
    return client.getPowerGenerated(source.getName(), now);
  }

  /**
   * Returns a sample Source. It's the first one returned by the WattDepot server in its index of
   * sources.
   * 
   * @return The sample Source.
   * @throws WattDepotClientException If problems occur getting the source index.
   */
  public Source getSampleSource() throws WattDepotClientException {
    SourceIndex index = client.getSourceIndex();
    SourceRef ref = index.getSourceRef().get(0);
    return client.getSource(ref);
  }

  /**
   * The main program that is invoked from 'java -jar wattdepot-cli.jar'.
   * 
   * @param args All args are ignored.
   * @throws Exception exception
   */
  public static void main(String[] args) throws Exception {
    CommandLineInterface cli = new CommandLineInterface();
    WattDepotCliProcessor proc = new WattDepotCliProcessor();
    List<String> commandParams;
    String command;
    String output = "";
    String userInput = "";
    System.out.println("Starting CLI.");
    Map<String, org.wattdepot.cli.command.WattDepotCliCommand> commandMap = new 
      HashMap<String, org.wattdepot.cli.command.WattDepotCliCommand>();
    commandMap.put("help", new Help());
    commandMap.put("listSources", new ListSources());
    commandMap.put("listSourceSummary", new ListSourceSummaryCommand());
    commandMap.put("listSensordataTimestamp", new ListSensordataTimestamp());
    commandMap.put("listSensordataDay", new ListSensordataDayCommand());
    commandMap.put("listPowerGeneratedTimestamp", new ListPowerGeneratedTimestampCommand()); 
    commandMap.put("listPowerGeneratedDay", new ListPowerGeneratedDayCommand());
    commandMap.put("listTotal", new ListTotalCommand());
    commandMap.put("chartPower", new ChartPowerCommand());
    commandMap.put("fueltypes", new FueltypesCommand());
    commandMap.put("totalpower", new TotalpowerCommand());
    commandMap.put("carboncontent", new CarboncontentCommand());
    while (true) {
      output = "";
      System.out.print("> ");
      BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
      if ((userInput = input.readLine()) == null) { 
        throw new Exception(); 
      } 
      commandParams = proc.tokenizeString(userInput);
      command = proc.getCommand(commandParams);     
      WattDepotCliCommand commandInstance = commandMap.get(command);
      if ("quit".equals(userInput)) {
        System.out.println("Exiting CLI.");
        break;
      }
      else if (commandInstance == null) {
        System.out.println("No such command");
      }
      else {
        output = commandInstance.doCommand(cli, commandParams);
        System.out.println(output);
      }    
    }
  }
}
